﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraGrid;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using ProgNetComponentsDx.Layout;
using DevExpress.Utils.Menu;
using System.Drawing;
using DevExpress.XtraGrid.Views.Grid.ViewInfo;

namespace System
{
    public static class GridExt
    {
        public static DataTable GetDataTable(this GridView gv)
        {
            if (gv.DataSource is DataTable)
                return gv.DataSource as DataTable;
            if (gv.DataSource is DataView)
                return (gv.DataSource as DataView).Table;
            if (gv.DataSource is BindingSource)
            {
                BindingSource bs = gv.DataSource as BindingSource;
                if (bs.DataSource is DataSet && (bs.DataSource as DataSet).Tables.Contains(bs.DataMember))
                    return (bs.DataSource as DataSet).Tables[bs.DataMember];
                if (bs.DataSource is DataTable)
                    return bs.DataSource as DataTable;
                if (bs.DataSource is DataView)
                    return (bs.DataSource as DataView).Table;
            }
            return null;
        }
        public static object GetRowUndetCursor(this GridView gv)
        {
            object obj = null;
            Point pt = gv.GridControl.PointToClient(Control.MousePosition);
            GridHitInfo info = gv.CalcHitInfo(pt);
            if (info.InRow || info.InRowCell)
                obj = gv.GetRow(info.RowHandle);
            return obj;
        }
        public static DataRow GetDataRowUndetCursor(this GridView gv)
        {
            DataRow obj = null;
            Point pt = gv.GridControl.PointToClient(Control.MousePosition);
            GridHitInfo info = gv.CalcHitInfo(pt);
            if (info.InRow || info.InRowCell)
                obj = gv.GetDataRow(info.RowHandle);
            return obj;
        }
        
        public static DataRow[] GetSelectedDataRows(this GridView view)
        {
            List<DataRow> list = new List<DataRow>();
            List<int> rowsId = new List<int>();
            int[] rows = view.GetSelectedRows();
            DataRow r = null;
            if (rows == null || rows.Length == 0)
            {
                rowsId.Add(view.FocusedRowHandle);
            }
            else
            {
                rowsId.AddRange(rows);
            }
            foreach (int i in rowsId)
            {
                if (view.IsGroupRow(i))
                {
                    list.AddRange(view.GetGroupDataRows(i));
                }
                else
                {
                    r = view.GetDataRow(i);
                    if (r != null)
                        list.Add(r);
                }
            }
            return list.ToArray();
        }
        public static DataRow[] GetGroupDataRows(this GridView view, int groupRowId)
        {
            List<DataRow> list = new List<DataRow>();
            List<int> rowsId = new List<int>();
            DataRow r = null;
            if (view.IsGroupRow(groupRowId))
            {
                int ct = view.GetChildRowCount(groupRowId);
                for (int i = 0; i < ct; i++)
                {
                    rowsId.Add(view.GetChildRowHandle(groupRowId, i));
                }
            }
            foreach (int i in rowsId)
            {
                if (view.IsGroupRow(i))
                {
                    list.AddRange(view.GetGroupDataRows(i));
                }
                else
                {
                    r = view.GetDataRow(i);
                    if (r != null)
                        list.Add(r);
                }
            }
            return list.ToArray();
        }
        public static void BestFitWithName(this ColumnView cv)
        {
            int width;
            try
            {
                foreach (GridColumn col in cv.Columns)
                {
                    width = col.FieldName.Mesure(cv.GridControl.Font).Width + 15;
                    col.BestFit();
                    if (col.Width < width)
                        col.Width = width;
                }
            }
            catch { }
        }

        public static GridView ExpandParentNode(this DataRow childRow, BaseView childView)
        {
            GridLevelNode node = null;
            GridLevelNode parentNode = null;
            DataRow parentRow = null;
            GridView gv = null;

            if (childView.SourceView != null)
                node = childView.GridControl.LevelTree.Find(childView.SourceView);
            else
                node = childView.GridControl.LevelTree.Find(childView);
            if (node != null && node.Parent != null)
            {
                parentNode = node.Parent;
                parentRow = childRow.GetParentRow(node.RelationName);
                if (!parentNode.IsRootLevel)
                {
                    gv = ExpandParentNode(parentRow, parentNode.LevelTemplate);
                }
                else
                    gv = parentNode.LevelTemplate as GridView;
                if (gv != null)
                {
                    int idx = -1;
                    for (int i = 0; i < parentRow.Table.Rows.Count; i++)
                    {
                        if (parentRow.Table.Rows[i].RowState == DataRowState.Deleted ||
                            parentRow.Table.Rows[i].RowState == DataRowState.Detached)
                        {
                            continue;
                        }
                        idx++;
                        if (parentRow == parentRow.Table.Rows[i])
                            break;

                    }
                    gv.SetMasterRowExpanded(gv.GetRowHandle(idx), true);
                    GridView g = gv.GetDetailView(gv.GetRowHandle(idx), gv.GetRelationIndex(gv.GetRowHandle(idx), node.RelationName)) as GridView;
                    return g;
                }
            }

            return null;
        }

        public static void CollapseAllDetails(this GridControl grid)
        {
            List<BaseView> views = new List<BaseView>();
            foreach (BaseView v in grid.Views)
            {
                views.Add(v);
            }
            foreach (BaseView v in views)
            {
                try
                {
                    if (v is GridView)
                    {
                        (v as GridView).CollapseAllDetails();
                    }
                }
                catch { }
            }
        }

        public static string GetLayoutXml(this BaseView view)
        {
            string layout = "";
            try
            {
                XmlDocument doc = new XmlDocument();
                XmlElement el = doc.CreateElement("View");

                if (view is GridView)
                {
                    GridView gv = view as GridView;
                    //el.AppendAttribute("NewItemRowPosition", gv.OptionsView.NewItemRowPosition);
                    el.AppendAttribute("RowHeight", gv.RowHeight);
                    el.AppendAttribute("ColumnPanelRowHeight", gv.ColumnPanelRowHeight);
                    el.AppendAttribute("ShowGroupPanel", gv.OptionsView.ShowGroupPanel);
                    el.AppendAttribute("ShowGroupedColumns", gv.OptionsView.ShowGroupedColumns);
                    el.AppendAttribute("ColumnAutoWidth", gv.OptionsView.ColumnAutoWidth);
                    el.AppendAttribute("ShowAutoFilterRow", gv.OptionsView.ShowAutoFilterRow);
                    el.AppendAttribute("NewItemRowPosition", gv.OptionsView.NewItemRowPosition);
                    XmlElement columns = doc.CreateElement("Columns");
                    foreach (GridColumn col in gv.Columns)
                    {
                        XmlElement c = doc.CreateElement(col.Name);
                        c.AppendAttribute("Width", col.Width);
                        c.AppendAttribute("Visible", col.Visible);
                        c.AppendAttribute("VisibleIndex", col.VisibleIndex);
                        c.AppendAttribute("SortIndex", col.SortIndex);
                        c.AppendAttribute("SortOrder", col.SortOrder);
                        c.AppendAttribute("GroupIndex", col.GroupIndex);
                        c.AppendAttribute("Fixed", col.Fixed);
                        c.AppendAttribute("FixedWidth", col.OptionsColumn.FixedWidth);
                        c.AppendAttribute("AutoFilterCondition", col.OptionsFilter.AutoFilterCondition);
                        columns.AppendChild(c);
                    }
                    el.AppendChild(columns);
                }
                doc.AppendChild(el);
                layout = doc.ToFormatedString();
            }
            catch (Exception ex) { ex.LogInternal(); }
            return layout;
        }
        public static void SetLayoutXml(this BaseView view, string xml, GridLayoutSettings settings = null)
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(xml);
                XmlElement el = doc.SelectSingleNode("View") as XmlElement;
                if (el != null)
                {
                    if (view is GridView)
                    {
                        GridView gv = view as GridView;
                        //gv.BeginDataUpdate();
                        //gv.SetFieldValue("deserializing", true);
                        gv.RowHeight = el.GetAttribute("RowHeight").AsInt();
                        gv.ColumnPanelRowHeight = el.GetAttribute("ColumnPanelRowHeight").AsInt();
                        gv.OptionsView.ShowGroupPanel = el.GetAttribute("ShowGroupPanel").AsBool();
                        
                        if (settings == null || settings.AllowColumnAutoWidthChange)
                            gv.OptionsView.ColumnAutoWidth = false;
                        if (settings == null || settings.AllowAutoFilterRowChange)
                            gv.OptionsView.ShowAutoFilterRow = el.GetAttribute("ShowAutoFilterRow").AsBool();
                        if (settings == null || settings.AllowShowGruppedColumsChange)
                            gv.OptionsView.ShowGroupedColumns = el.GetAttribute("ShowGroupedColumns").AsBool();
                        if (settings == null || settings.AllowNewItemRowPositionChange)
                            gv.OptionsView.NewItemRowPosition = gv.OptionsView.NewItemRowPosition.FromObject(el.GetAttribute("NewItemRowPosition"));
                        
                        XmlElement columns = el.SelectSingleElement("Columns");
                        if (columns != null)
                        {
                            List<GridColumnHelper> cols = new List<GridColumnHelper>();
                           
                            List<GridColumn> visible = new List<GridColumn>();

                            foreach (GridColumn c in gv.Columns)
                            {
                                cols.Add(new GridColumnHelper(c));
                                if (c.VisibleIndex > -1)
                                    visible.Add(c);
                            }

                            foreach (GridColumn c in gv.Columns)
                            {
                                c.Visible = false;
                                c.SortIndex = -1;
                                c.GroupIndex = -1;
                            }

                            GridColumn col;
                            foreach (GridColumnHelper h in cols)
                            {
                                col = h.Column;
                                XmlElement c = columns.SelectSingleElement(col.Name);
                                if (c != null)
                                {
                                    col.Width = c.GetAttribute("Width").AsInt();
                                    col.Visible = c.GetAttribute("Visible").AsBool();
                                   
                                    h.VisibleIndex = c.GetAttribute("VisibleIndex").AsInt();
                                    h.SortIndex = c.GetAttribute("SortIndex").AsInt();
                                    h.GroupIndex = c.GetAttribute("GroupIndex").AsInt();

                                    //col.VisibleIndex = c.GetAttribute("VisibleIndex").AsInt();
                                    //col.SortIndex = c.GetAttribute("SortIndex").AsInt();
                                    //col.GroupIndex = c.GetAttribute("GroupIndex").AsInt();
                                    

                                    col.SortOrder = col.SortOrder.FromObject(c.GetAttribute("SortOrder"));
                                    if (settings == null || settings.AllowColumnsAutoFilterConditionChange)
                                        col.OptionsFilter.AutoFilterCondition = col.OptionsFilter.AutoFilterCondition.FromObject(c.GetAttribute("AutoFilterCondition"));
                                    if (settings == null || settings.AllowColumnsFixedChange)
                                        col.Fixed = col.Fixed.FromObject(c.GetAttribute("Fixed"));
                                    if (settings == null || settings.AllowColumnsFixedWidthChange)
                                        col.OptionsColumn.FixedWidth = c.GetAttribute("FixedWidth").AsBool();
                                    
                                    if (visible.Contains(h.Column))
                                        visible.Remove(h.Column);
                                }
                            }
                            //#region probably not needed if GridControl.BeginInit() - GridControl.EndInit()
                            #region set VisibleIndex
                            cols.Sort(GridColumnHelperComparerForVisibleIndex.Instance);
                            GridColumnHelper[] tab = cols.ToArray();
                            foreach (GridColumnHelper h in tab)
                            {
                                if (h.VisibleIndex > -1)
                                {
                                    h.Column.VisibleIndex = h.VisibleIndex;
                                    h.VisibleIndex = -1;
                                }
                            }
                            
                            #endregion

                            #region Set SortIndex
                            cols.Sort(GridColumnHelperComparerForSortIndex.Instance);
                            tab = cols.ToArray();
                            foreach (GridColumnHelper h in tab)
                            {
                                if (h.SortIndex > -1)
                                {
                                    h.Column.SortIndex = h.SortIndex;
                                    h.SortIndex = -1;
                                }
                            }
                            
                            #endregion

                            #region Set GroupIndex
                            cols.Sort(GridColumnHelperComparerForGroupIndex.Instance);
                            tab = cols.ToArray();
                            foreach (GridColumnHelper h in tab)
                            {
                                if (h.GroupIndex > -1)
                                {
                                    h.Column.GroupIndex = h.GroupIndex;
                                    h.SortIndex = -1;
                                }
                            }

                            #endregion
                            
                            cols.Clear();
                             
                            //#endregion
                            foreach (GridColumn c in visible)
                            {
                                c.VisibleIndex = gv.VisibleColumns.Count;
                            }
                            visible.Clear();
                        }
                        if (settings == null || settings.AllowColumnAutoWidthChange)
                            gv.OptionsView.ColumnAutoWidth = el.GetAttribute("ColumnAutoWidth").AsBool();
                        //gv.SetFieldValue("deserializing", false);
                        //gv.EndDataUpdate();
                    }
                }
            }
            catch (Exception ex) { ex.LogInternal(); }
        }

        /// <summary>
        /// For each visible row in the grid, sets value for specified column
        /// </summary>
        /// <param name="view"></param>
        /// <param name="column"></param>
        /// <param name="value"></param>
        public static void SetAllRowCellValue(this GridView view, GridColumn column, object value)
        {
            if (view != null && column != null)
            {
                view.BeginDataUpdate();
                try
                {
                    for (int i = 0; i < view.RowCount; i++)
                    {
                        view.SetRowCellValue(i, column, value);
                    }
                }
                finally
                {
                    view.EndDataUpdate();
                }
            }
        }
        
        private class GridColumnHelper
        {
            public GridColumnHelper(GridColumn col)
            {
                Column = col;
                VisibleIndex = col.VisibleIndex;
                SortIndex = col.SortIndex;
                GroupIndex = col.GroupIndex;
            }
            public GridColumn Column
            {
                get;
                set;
            }
            public int VisibleIndex
            {
                get;
                set;
            }
            public int SortIndex
            {
                get;
                set;
            }
            public int GroupIndex
            {
                get;
                set;
            }
        }

        private class GridColumnHelperComparerForVisibleIndex : IComparer<GridColumnHelper>
        {
            public static GridColumnHelperComparerForVisibleIndex Instance = new GridColumnHelperComparerForVisibleIndex();

            public int Compare(GridColumnHelper x, GridColumnHelper y)
            {
                return x.VisibleIndex.CompareTo(y.VisibleIndex);
            }
        }
        private class GridColumnHelperComparerForGroupIndex : IComparer<GridColumnHelper>
        {
            public static GridColumnHelperComparerForGroupIndex Instance = new GridColumnHelperComparerForGroupIndex();

            public int Compare(GridColumnHelper x, GridColumnHelper y)
            {
                return x.GroupIndex.CompareTo(y.GroupIndex);
            }
        }
        private class GridColumnHelperComparerForSortIndex : IComparer<GridColumnHelper>
        {
            public static GridColumnHelperComparerForSortIndex Instance = new GridColumnHelperComparerForSortIndex();

            public int Compare(GridColumnHelper x, GridColumnHelper y)
            {
                return x.SortIndex.CompareTo(y.SortIndex);
            }
        }
    }
    public static class GridViewMenuExport
    {
        private static Dictionary<GridView, GridExportSettings> GridSettings = new Dictionary<GridView, GridExportSettings>();

        public class GridExportSettings
        {
            public static readonly GridExportSettings DefaultSettings = new GridExportSettings();

            public GridExportSettings()
            {
                this.ExportToHtml = true;
                this.ExportToPdf = true;
                this.ExportToXls = true;
                this.ExportToXlsx = true;
                ExportMenuCaption = "Eksportuj";
            }
            public string ExportMenuCaption
            {
                get;
                set;
            }
            public bool ExportToXls { get; set; }
            public bool ExportToXlsx { get; set; }
            public bool ExportToPdf { get; set; }
            public bool ExportToHtml { get; set; }
        }
        public static void AddExportMenu(this GridView gv)
        {
            gv.AddExportMenu(GridExportSettings.DefaultSettings);
        }
        public static void AddExportMenu(this GridView gv, GridExportSettings settings)
        {
            if (GridSettings.ContainsKey(gv))
                GridSettings.Remove(gv);

            GridSettings.Add(gv, settings);
            gv.PopupMenuShowing -= new PopupMenuShowingEventHandler(gv_PopupMenuShowing);
            gv.PopupMenuShowing += new PopupMenuShowingEventHandler(gv_PopupMenuShowing);
        }
        static void gv_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e)
        {
            GridView gv = sender as GridView;
            if (GridSettings.ContainsKey(gv))
            {
                GridExportSettings s = GridSettings[gv];
                DevExpress.Utils.Menu.DXSubMenuItem exportItem = new DevExpress.Utils.Menu.DXSubMenuItem(s.ExportMenuCaption);
                DXMenuItem item;
                if (s.ExportToHtml)
                {
                    item = new DXMenuItem("HTML", ExportToHtml);
                    item.Tag = gv;
                    exportItem.Items.Add(item);
                }
                if (s.ExportToPdf)
                {
                    item = new DXMenuItem("PDF", ExportToPdf);
                    item.Tag = gv;
                    exportItem.Items.Add(item);
                }
                if (s.ExportToXls)
                {
                    item = new DXMenuItem("XLS", ExportToXls);
                    item.Tag = gv;
                    exportItem.Items.Add(item);
                }
                if (s.ExportToXlsx)
                {
                    item = new DXMenuItem("XLSX", ExportToXlsx);
                    item.Tag = gv;
                    exportItem.Items.Add(item);
                }

                if (exportItem.Items.Count > 0)
                    e.Menu.Items.Add(exportItem);
            }
        }

        private static void ExportToHtml(object sender, EventArgs e)
        {
            DXMenuItem item = sender as DXMenuItem;
            if (item != null && item.Tag != null && item.Tag is GridView)
            {
                GridView gv = item.Tag as GridView;
                string file = GetFileName("html");
                if (file.IsNotNull())
                {
                    try
                    {
                        gv.ExportToHtml(file);
                    }
                    catch
                    {

                    }
                }
            }
        }
        private static void ExportToPdf(object sender, EventArgs e)
        {
            DXMenuItem item = sender as DXMenuItem;
            if (item != null && item.Tag != null && item.Tag is GridView)
            {
                GridView gv = item.Tag as GridView;
                string file = GetFileName("pdf");
                if (file.IsNotNull())
                {
                    try
                    {
                        gv.ExportToPdf(file);
                    }
                    catch
                    {

                    }
                }
            }
        }
        private static void ExportToXls(object sender, EventArgs e)
        {
            DXMenuItem item = sender as DXMenuItem;
            if (item != null && item.Tag != null && item.Tag is GridView)
            {
                GridView gv = item.Tag as GridView;
                string file = GetFileName("xls");
                if (file.IsNotNull())
                {
                    try
                    {
                        gv.ExportToXls(file);
                    }
                    catch
                    {

                    }
                }
            }
        }
        private static void ExportToXlsx(object sender, EventArgs e)
        {
            DXMenuItem item = sender as DXMenuItem;
            if (item != null && item.Tag != null && item.Tag is GridView)
            {
                GridView gv = item.Tag as GridView;
                string file = GetFileName("xlsx");
                if (file.IsNotNull())
                {
                    try
                    {
                        gv.ExportToXlsx(file);
                    }
                    catch
                    {

                    }
                }
            }
        }

        private static string GetFileName(string ext)
        {
            string file = string.Empty;
            using (SaveFileDialog dlg = new SaveFileDialog())
            {
                dlg.CheckFileExists = false;
                dlg.DefaultExt = "." + ext;
                dlg.Filter = ext + "|*." + ext;
                dlg.FileName = "dane." + ext;
                dlg.AddExtension = true;
                if (dlg.ShowDialog() == DialogResult.OK)
                    file = dlg.FileName;
            }
            return file;
        }

    }
}
